package com.naive.imperative.view;

import java.util.ArrayList;
import java.util.List;

import android.graphics.RectF;

import com.naive.imperative.program.Operation;

public abstract class OperationRenderer {
	private final RectF frame;
	private final Operation operation;
	private final List<OperationRenderer> renderers;
	private final List<TapArea> areas;

	private boolean layoutInvalid;

	public OperationRenderer(Operation o) {
		operation = o;
		frame = new RectF();
		renderers = new ArrayList<OperationRenderer>();
		areas = new ArrayList<TapArea>();
	}

	public abstract TapArea probe(float x, float y);

	public abstract float getPreferredWidth(RenderingContext rc);

	public abstract void draw(RenderingContext c);

	protected abstract void doLayout(LayoutContext lc);

	public float getPreferredHeight(RenderingContext rc) {
		return rc.getTextHeight();
	}

	protected Operation getOperation() {
		return operation;
	}

	public Iterable<OperationRenderer> getRenderers() {
		return renderers;
	}

	public void replace(Operation childOperation, OperationRenderer r) {
		final int index = locateIndex(childOperation);
		if (index == -1) {
			throw new IllegalArgumentException();
		}
		
		renderers.set(index, r);
		setNeedsLayout();
	}

	public OperationRenderer locate(float x, float y) {
		for (OperationRenderer r : renderers) {
			if (r.getFrame().contains(x, y)) {
				return r;
			}
		}
		return null;
	}

	protected void setNeedsLayout() {
		layoutInvalid = true;
	}

	protected void validateLayout(RenderingContext rc) {
		if (layoutInvalid) {
			LayoutContext layoutContext = new LayoutContext(rc);
			doLayout(layoutContext);
			layoutInvalid = false;
		}
	}

	public RectF getFrame() {
		return frame;
	}

	public void setOrigin(float x, float y) {
		frame.set(x, y, frame.width() + x, frame.height() + y);
	}

	public void setSize(float w, float h) {
		frame.set(frame.left, frame.top, frame.left + w, frame.top + h);
		setNeedsLayout();
	}

	protected int locateIndex(Operation o) {
		for (int i = 0; i < renderers.size(); i++) {
			if (renderers.get(i).getOperation() == o) {
				return i;
			}
		}
		return -1;
	}

	protected void drawTapAreas(RenderingContext rc) {
		for (TapArea ta : areas) {
			ta.draw(rc);
		}
	}

	protected void drawChildren(RenderingContext r) {
		for (OperationRenderer child : renderers) {
			final RectF f = child.getFrame();
			r.translate(f.left, f.top);
			child.draw(r);
			r.untranslate(f.left, f.top);
		}
	}
}
